#ifndef __application_H__
#define __application_H__

// #include "bs_type.h"
#include "bs_app_conf.h"
#include "string.h"
#include "math.h"
#include "systick.h"

#include <stdint.h>
#include "dev_key.h"
#include "dev_buzzer.h"
#include "dev_flash.h"
#include "dev_led.h"
#include "bs_command.h"
#include "bs_ring_buf.h"
#include "bs_crc.h"
#include <stdio.h>
#include "bffs.h"
#include "image_mgr.h"
#include "fmc_operation.h"
#include "inner_flash.h"

#ifdef __cplusplus
extern "C" {
#endif

#define BS_MIN(a,b)                (((a)<(b))?(a):(b))
#define BS_MAX(a,b)                (((a)>(b))?(a):(b))
#define BS_PROTOCOL_TIMEOUT        1000

// flash 读取控制参数
#define FILE_BLOCK_BITS            12
#define FILE_BLOCK_SIZE            4096

#define BS_DMA_CLOCK               0
#define BS_DMA_DATA_OUT            1
#define BS_DMA_DATA_IN             2

#define DATA_16B_PACK(data)   ((uint16_t)data<<8 | (uint8_t)~data)
#define FLASH_WRITE_QUEUE_LENGTH          4
#define __ROUNDDOWN(x, y)                 ((x)- (x) % (y))

#define MSG_KEYUP                  0
#define MSG_KEYDOWN                1
#define MSG_KEY_ENTER              2            
#define MSG_KLONGPRESS             3

typedef enum {
    IDLE,
    LINKING,
    LINKED,
    WAIT_BEFORE_ERASE,
    ERASE,
    RELEASET_WRITE_PROTECT,
    WAIT_ERASE,
    WRITE_FLASH,
    WRITE_FLASH_WAIT_DATA1,
    WRITE_FLASH_DATA_READY1,
    WRITE_FLASH2,
    WRITE_FLASH3,
    WRITE_FLASH_WAIT_DATA2,
    WRITE_FLASH_DATA_READY2,
    WRITE_FLASH4,
    WRITE_FLASH5,
    WRITE_FLASH_WAIT1,
    WRITE_FLASH10,
    WRITE_FLASH11,
    WRITE_FLASH12,

    WAIT_WRITE_FLASH1,
    WRITE_READBACK_A,
    WRITE_READBACK_A_WAIT,
    WAIT_WRITE_FLASH2,
    WAIT_WRITE_FLASH3,
    WRITE_READBACK_B,
    WRITE_READBACK_B_WAIT,
    WAIT_WRITE_FLASH4,
    WAIT_BRK_POINT,
    WAIT_BRK_POINT2,
    WAIT_ERASE_ERR,
    FAILED_READ_ICE_STATE_REG,
    FAILED_TIMEOUT_READ_ICE_STATE_REG,
    FAILED_SET_ADDR_AND_LEN,
    FAILED_WRITE_SRAM_A,
    FAILED_WRITE_SRAM_B,
    FAILED_DISABLE_WRITE_PROTECT,
    FAILED_WRITE_SRAMA_TO_FLASH,
    FAILED_WRITE_SRAMB_TO_FLASH,

    FAILED_TIMEOUT_REDA_ICE_STATE_REG,
    FINISH,
    FINISH_WAIT,
    FINISH_RESET,

    LINKING_TIMEOUT,
    WRITER_WR_TIME_OUT,
    WRITER_RD_TIME_OUT,
    FAILED_READBACK_A,
    FAILED_READBACK_B,
    WRITE_OVER,
    EXIT_ERROR,
    WRITER_ERROR,
} bs_writer_schedu_t;


static const char *sched2str[] = {
    [IDLE] = "IDLE",
    [LINKING] = "LINKING",
    [LINKED] = "LINKED",
    [WAIT_BEFORE_ERASE] = "WAIT_BEFORE_ERASE",
    [ERASE] = "ERASE",
    [RELEASET_WRITE_PROTECT] = "RELEASET_WRITE_PROTECT",
    [WAIT_ERASE] = "WAIT_ERASE",
    [WRITE_FLASH] = "WRITE_FLASH",
    [WRITE_FLASH_WAIT_DATA1] = "WRITE_FLASH_WAIT_DATA1",
    [WRITE_FLASH_DATA_READY1] = "WRITE_FLASH_DATA_READY1",
    [WRITE_FLASH2] = "WRITE_FLASH2",
    [WRITE_FLASH3] = "WRITE_FLASH3",
    [WRITE_FLASH_WAIT_DATA2] = "WRITE_FLASH_WAIT_DATA2",
    [WRITE_FLASH_DATA_READY2] = "WRITE_FLASH_DATA_READY2",
    [WRITE_FLASH4] = "WRITE_FLASH4",
    [WRITE_FLASH5] = "WRITE_FLASH5",
    [WRITE_FLASH_WAIT1] = "WRITE_FLASH_WAIT1",
    [WRITE_FLASH10] = "WRITE_FLASH10",
    [WRITE_FLASH11] = "WRITE_FLASH11",
    [WRITE_FLASH12] = "WRITE_FLASH12",

    [WAIT_WRITE_FLASH1] = "WAIT_WRITE_FLASH1",
    [WRITE_READBACK_A] = "WRITE_READBACK_A",
    [WRITE_READBACK_A_WAIT] = "WRITE_READBACK_A_WAIT",
    [WAIT_WRITE_FLASH2] = "WAIT_WRITE_FLASH2",
    [WAIT_WRITE_FLASH3] = "WAIT_WRITE_FLASH3",
    [WRITE_READBACK_B] = "WRITE_READBACK_B",
    [WRITE_READBACK_B_WAIT] = "WRITE_READBACK_B_WAIT",
    [WAIT_WRITE_FLASH4] = "WAIT_WRITE_FLASH4",
    [WAIT_BRK_POINT] = "WAIT_BRK_POINT",
    [WAIT_BRK_POINT2] = "WAIT_BRK_POINT2",
    [WAIT_ERASE_ERR] = "WAIT_ERASE_ERR",
    [FAILED_READ_ICE_STATE_REG] = "FAILED_READ_ICE_STATE_REG",
    [FAILED_TIMEOUT_READ_ICE_STATE_REG] = "FAILED_TIMEOUT_READ_ICE_STATE_REG",
    [FAILED_SET_ADDR_AND_LEN] = "FAILED_SET_ADDR_AND_LEN",
    [FAILED_WRITE_SRAM_A] = "FAILED_WRITE_SRAM_A",
    [FAILED_WRITE_SRAM_B] = "FAILED_WRITE_SRAM_B",
    [FAILED_DISABLE_WRITE_PROTECT] = "FAILED_DISABLE_WRITE_PROTECT",
    [FAILED_WRITE_SRAMA_TO_FLASH] = "FAILED_WRITE_SRAMA_TO_FLASH",
    [FAILED_WRITE_SRAMB_TO_FLASH] = "FAILED_WRITE_SRAMB_TO_FLASH",

    [FAILED_TIMEOUT_REDA_ICE_STATE_REG] = "FAILED_TIMEOUT_REDA_ICE_STATE_REG",
    [FINISH] = "FINISH",
    [FINISH_WAIT] = "FINISH_WAIT",
    [FINISH_RESET] = "FINISH_RESET",

    [LINKING_TIMEOUT] = "LINKING_TIMEOUT",
    [WRITER_WR_TIME_OUT] = "WRITER_WR_TIME_OUT",
    [WRITER_RD_TIME_OUT] = "WRITER_RD_TIME_OUT",
    [FAILED_READBACK_A] = "FAILED_READBACK_A",
    [FAILED_READBACK_B] = "FAILED_READBACK_B",
    [WRITE_OVER] = "WRITE_OVER",
    [EXIT_ERROR] = "EXIT_ERROR",
    [WRITER_ERROR] = "WRITER_ERROR",
};

typedef struct {
    uint32_t            dmax;        // DMA0 DMA1
    uint32_t            chan;        // DMA channel
    uint32_t            sub_peri;    // DMA_SUBPERIx
} bs_dma_desc_t;


typedef enum {
	IOC_WR_END,
    IOC_RD_END,
} bs_writer_trans_t;


typedef struct {
    uint32_t            spix;           // SPI0 SPI1
    uint32_t            timx;           // TIMERx UP event
    unsigned char       *tx_buf;        // DMA buffer
    unsigned char       *rx_buf;
    uint32_t            tx_count;       // DMA size(byte)
    uint32_t            rx_count;
    uint32_t            *clock_data;    // pwm data
    bs_dma_desc_t       dma_chan[3];    // TIMER DMA, SPI_TX DMA, SPI_RX_DMA
    uint32_t            pulse_cnt;
} bs_writer_drv_t;

// 文件缓冲区描述符 请求项
typedef struct bs_sf_request {
    uint32_t      b_addr;                // flash 地址, 
    uint32_t      b_blocknr;             // 用来标识当前缓存块是否有效
    uint32_t      b_size;                // 当前请求的大小，即DMA数量
    uint8_t       nr_sectors;
    uint8_t       cmd;
    int           timeout;
    uint8_t       *b_data;
    uint8_t       b_lock;
    uint8_t       b_update;
    uint8_t       b_dirt;
} bs_sf_request_t;

typedef enum {
    SF_IDLE,
    SF_ERASER,
    SF_ERASER_BUSY,
    SF_ERASER_CMPLT,

    SF_WRITE_PAGE,
    SF_WRITE_PAGE_CMPLT,
    SF_WRITE_PAGE_BUSY,
    SF_WRITE_SECTOR_CMPLT,
}bs_sf_state_t;

typedef struct bs_sf_dev {
    bs_sf_state_t      state;                // 当前设备的状态
    uint32_t           lock;                 // 设备锁
    bs_sf_request_t    *cur_rd_req;          // 当前请求项
    bs_sf_request_t    *cur_wr_req;          // 当前请求项
    uint32_t           s_wait;               // 请求项计数
}bs_sf_dev_t;


// #pragma pack(push,1)
// typedef struct bs_timespec {
//     uint16_t        tm_year;
//     uint8_t         tm_mon;
//     uint8_t         tm_day;
//     uint8_t         tm_hour;
//     uint8_t         tm_min;
//     uint8_t         tm_sec;
//     uint16_t        tm_msec;
// } bs_timespec_t;
// #pragma pack(pop)


typedef struct bs_file_struct {
    uint32_t        start_blk;            // 起始扇区
    uint32_t        f_size;               // 文件大小
    uint32_t        f_buf_size;
    uint32_t        f_pos;                // 相对地址
    uint32_t        flag;

    uint8_t*        f_buf_base;           // 读写缓冲区
    uint8_t*        f_buf_end;            // sram buff最后一个地址+1
    uint8_t*        f_write_ptr;
    
    uint32_t        f_user_left;          // 异步读取时，保存用户需要读取的长度
    uint8_t         *f_user_buf;          // 异步读取时，保存用户buffer的指针

    uint8_t         f_seg;                // 预读时用来标识当前有效区域
    int             state;                // 异步操作状态机
    bs_sf_request_t f_buf_desc[2];  // 预读时需要两个描述符
    void*           f_owner;
} bs_file_t;


typedef struct bs_writer_ctx{
    bs_writer_schedu_t  schedu;
    unsigned char       channel;
    uint32_t            fw_len;
    uint32_t            cur_fw_len;
    uint32_t            cur_fw_addr;
    int32_t             timeout;
    unsigned char       *fw_data;
    unsigned char       *fw_base;
    uint8_t             region;
    uint8_t             tmp_send_buf[540];
    uint32_t            int_point;
    uint32_t            errors;
    uint32_t            user_var;
    char                *fw_name;
#if FS_TYPE
    FIL                  fw_file;
#else
    bs_file_t            fw_file;           // 这是个虚拟文件，每次都从这里获取数据
#endif
    bs_writer_drv_t     *drv;
    int  (*read)(struct  bs_writer_ctx *ctx, unsigned char *buf, int size);
    int (*write)(struct  bs_writer_ctx *ctx, unsigned char *buf, int size);
    int (*ioctl)(struct  bs_writer_ctx *ctx, bs_writer_trans_t cmd);
} bs_writer_ctx_t;


int bs_writer_init(bs_writer_ctx_t *ctx, unsigned char channel);
int  bs_writer_test(bs_writer_ctx_t *ctx);


int f2_open(bs_file_t *fp);
int f2_close(bs_file_t *fp);
int f2_flush(bs_file_t *fp);

int f2_write(bs_file_t *fp, void *buf, uint32_t len);
int f2_read(bs_file_t *fp, void *buf, uint32_t len);
int f2_bread(bs_file_t *fp, void *buf, uint32_t len);
int f2_ioctl(bs_file_t *fp, int cmd);

extern int bs_jiffies;
extern void bs_device_rtc_init(void);
void rtc_show_time(void);
void rtc_acquire_time(uint8_t *data);
int bs_rtc_setup(uint8_t *time_para);
void bs_spiflash_process(void);
void bs_sf_device_init(void);
void bs_sf_make_request(bs_sf_request_t *bd, int cmd);


void bs_write_bkp_reg(uint8_t reg, uint32_t data);
uint32_t bs_read_bkp_reg(uint8_t reg);

void bs_dev_lcd_init(void);
void bs_lcd_process(void);


extern char*      fmware_name;

#ifdef __cplusplus
}
#endif

#endif /* __com_protocol_H__ */
